#pragma once
#include "Mutex.hpp"
#include "Cond.hpp"
#include <iostream>
#include <queue>

namespace BlockQueueModule
{
    using namespace LockModule;
    using namespace CondModule;
    
    static int gcap = 10;
    template<typename T>
    class BlockQueue
    {
    private:
        bool IsFull()
        {
            return _cap == _q.size();
        }
        bool IsEmpty()
        {
            return _q.empty();
        }
    public:
        BlockQueue(int cap = gcap):_cap(cap),_cwait(0),_pwait(0)
        {}
        void Enqueue(const T& in)//为了防止伪唤醒，我们通常使用while进行判断
        {
            LockGuard lockguard(_mutex);
            //_mutex.Lock();
            while(IsFull())
            {
                std::cout << "生产者进入等待..." << std::endl;
                _pwait++;
                _Productor_cond.Wait(_mutex);
                _pwait--;
                std::cout << "生产者被唤醒..." << std::endl;
            }
            _q.push(in);
            if(_cwait > 0)
            {
                std::cout << "叫醒消费者" << std::endl;
                _Consumer_cond.Notify();
            }
            //_mutex.unlock();
        }
        void pop(T* out)
        {
            LockGuard lockguard(_mutex);
            //_mutex.Lock();
            while(IsEmpty())
            {
                std::cout << "消费者进入等待..." << std::endl;
                _cwait++;
                _Consumer_cond.Wait(_mutex);
                _cwait--;
                std::cout << "消费者被唤醒..." << std::endl;
            }
            *out = _q.front();
            _q.pop();
            if(_pwait > 0)
            {
                std::cout << "叫醒生产者" << std::endl;
                _Productor_cond.Notify();
            }
            //_mutex.unlock();
        }
        ~BlockQueue()
        {}
    private:
        std::queue<T> _q;
        int _cap;
        Mutex _mutex;
        Cond _Productor_cond;
        Cond _Consumer_cond;
        int _cwait;
        int _pwait;
    };






    // vesion 1
    // static const int gcap = 10;

    // template <typename T>
    // class BlockQueue
    // {
    // private:
    //     bool IsFull() { return _q.size() == _cap; }
    //     bool IsEmpty() { return _q.empty(); }

    // public:
    //     BlockQueue(int cap = gcap) : _cap(cap), _cwait_num(0), _pwait_num(0)
    //     {
    //         pthread_mutex_init(&_mutex, nullptr);
    //         pthread_cond_init(&_productor_cond, nullptr);
    //         pthread_cond_init(&_consumer_cond, nullptr);
    //     }
    //     void Equeue(const T &in) // 生产者
    //     {
    //         pthread_mutex_lock(&_mutex);
    //         while (IsFull()) //对条件进行判断，为了防止伪唤醒，我们通常使用while进行判断！
    //         {
    //             std::cout << "生产者进入等待..." << std::endl;

    //             _pwait++;
    //             pthread_cond_wait(&_productor_cond, &_mutex); // wait的时候，必定是持有锁的
    //             _pwait--;
    //             //线程被唤醒&&重新申请并持有锁(它会在临界区内醒来！)

    //             std::cout << "生产者被唤醒..." << std::endl;

    //         }
    //         _q.push(in);

    //         // 肯定有数据！
    //         if(_cwait)
    //         {
    //             std::cout << "叫醒消费者" << std::endl;
    //             pthread_cond_signal(&_consumer_cond);
    //         }
    //         pthread_mutex_unlock(&_mutex);
    //     }
    //     void Pop(T *out) // 消费者
    //     {
    //         pthread_mutex_lock(&_mutex);
    //         while(IsEmpty())
    //         {
    //             std::cout << "消费者进入等待..." << std::endl;
    //             _cwait++;
    //             pthread_cond_wait(&_consumer_cond, &_mutex); // 伪唤醒
    //             _cwait--;
    //             std::cout << "消费者被唤醒..." << std::endl;
    //         }
    //         *out = _q.front();
    //         _q.pop();

    //         // 肯定有空间
    //         if(_pwait)
    //         {
    //             std::cout << "叫醒生产者" << std::endl;
    //             pthread_cond_signal(&_productor_cond);
    //         }

    //         pthread_mutex_unlock(&_mutex);
    //     }
    //     ~BlockQueue()
    //     {
    //         pthread_mutex_destroy(&_mutex);
    //         pthread_cond_destroy(&_productor_cond);
    //         pthread_cond_destroy(&_consumer_cond);
    //     }

    // private:
    //     std::queue<T> _q;               // 保存数据的容器，临界资源
    //     int _cap;                       // bq最大容量
    //     pthread_mutex_t _mutex;         // 互斥
    //     pthread_cond_t _productor_cond; // 生产者条件变量
    //     pthread_cond_t _consumer_cond;  // 消费者条件变量

    //     int _cwait;
    //     int _pwait;
    // };
}